package com.lagou.ipersistence.binding;

import com.lagou.ipersistence.mapping.MappedStatement;
import com.lagou.ipersistence.mapping.SQLCommandType;
import com.lagou.ipersistence.session.Configuration;
import com.lagou.ipersistence.session.SqlSession;

import java.lang.reflect.Method;

/**
 * @author Yan Jiahong
 * Created on 2020/11/22
 */
public class MapperMethod {
  private final SqlCommand command;
  private final MethodSignature method;
  
  public MapperMethod(Class<?> mappedInterface, Method method, Configuration configuration) {
    this.command = new SqlCommand(configuration, mappedInterface, method);
    this.method = new MethodSignature(configuration, mappedInterface, method);
  }
  
  public Object execute(SqlSession sqlSession, Object[] args) {
    Object result = null;
    switch (command.getType()) {
      case INSERT:
        result = sqlSession.insert(command.getName(), args[0]);
        break;
      case DELETE:
        result = sqlSession.delete(command.getName(), args[0]);
        break;
      case UPDATE:
        result = sqlSession.update(command.getName(), args[0]);
        break;
      case SELECT:
        result = sqlSession.selectOne(command.getName(), args[0]);
        break;
      default:
        break;
    }
    return result;
  }
  
  
  public static class SqlCommand {
    private final String name;
    private final SQLCommandType type;
    
    /**
     * @param mappedInterface Mapper接口类
     * @param method          mapper接口中的方法
     */
    public SqlCommand(Configuration configuration, Class<?> mappedInterface, Method method) {
      final String methodName = method.getName();
      MappedStatement ms = resolveMappedStatement(mappedInterface, methodName, configuration);
      if (ms == null) {
        throw new BindingException("无效的statement(没有找到): " + mappedInterface.getName() + "." + methodName);
      }
      name = ms.getId();
      type = ms.getSqlCommandType();
    }
    
    private MappedStatement resolveMappedStatement(Class<?> mapperInterface, String methodName,
                                                   Configuration configuration) {
      String statementId = mapperInterface.getName() + "." + methodName;
      if (configuration.hasStatement(statementId)) {
        return configuration.getMappedStatement(statementId);
      }
      return null;
    }
    
    public String getName() {
      return name;
    }
    
    public SQLCommandType getType() {
      return type;
    }
  }
  
  public static class MethodSignature {
    private final boolean returnMany;
    private final boolean returnVoid;
    private final Class<?> returnType;
    
    public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
      this.returnType = method.getReturnType();
      this.returnVoid = void.class.equals(this.returnType);
      this.returnMany = configuration.getObjectFactory().isCollection(returnType);
    }
  }
}
